package com.qc31.monitorlib.ui.video

import android.annotation.SuppressLint
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import io.reactivex.rxjava3.subjects.PublishSubject
import java.io.IOException
import java.io.OutputStream
import java.net.HttpURLConnection
import java.net.URL
import java.util.*
import java.util.concurrent.ConcurrentLinkedDeque
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread

/** @author joker @date 2022/7/23$ 11:14$ */
class TalkHelper   {
    //缓冲区字节大小
    private var bufferSize = 0

    //是否已关闭录音
    private var isClosed = false

    //是否正在录音
    private var isRecording = false

    //录音文件队列
    private var dataQueue: Queue<ShortArray>? = ConcurrentLinkedDeque()

    //录音
    private var audioRecord: AudioRecord? = null

    //录音状态
    private var state = 0
    private val executorService: ExecutorService by lazy { Executors.newFixedThreadPool(5) }

    private val talkSocket=PublishSubject.create<Boolean>()
    fun talkObserver()=talkSocket.hide()

    @SuppressLint("MissingPermission")
    private fun initAudioRecord() {
        if (audioRecord == null) {
            bufferSize =
                AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING)
            check(bufferSize > 0) { "没有最小buffer" }
            audioRecord = AudioRecord(
                AUDIO_INPUT,
                AUDIO_SAMPLE_RATE,
                AUDIO_CHANNEL,
                AUDIO_ENCODING,
                bufferSize
            )
            state = STATUS_READY
        }
    }

    /** 开启录音 */
    private fun startRecord() {
        if (audioRecord!!.state == AudioRecord.STATE_INITIALIZED) {
            state = STATUS_START
            audioRecord!!.startRecording()
            recording()
        }
    }

    /** 开始录音 */
    private fun recording() {
        val buffer = ShortArray(bufferSize)
        state = STATUS_RECORDING
        isRecording = true
        while (isRecording) {
            audioRecord?.read(buffer, 0, bufferSize)
            dataQueue?.add(buffer)
        }
    }

    /** 结束录音 */
    fun stopRecord() {
        if (audioRecord == null) return
        if (audioRecord!!.state == AudioRecord.STATE_INITIALIZED) {
            audioRecord!!.stop()
            state = STATUS_STOP
        }
        release()
    }

    /** 销毁录音 */
    fun destroy() {
        release()
        dataQueue!!.clear()
        dataQueue = null
        stopService()
    }

    /** 重置 */
    private fun release() {
        isRecording = false
        isClosed = true
        if (audioRecord != null) {
            audioRecord!!.release()
            audioRecord = null
        }
        thread {
            closeHttp()
        }
    }

    /**
     */
    fun start(url: String) {
        executorService.execute { initHttp(url) }
        executorService.execute { initDataQueue() }
        executorService.execute {
            initAudioRecord()
            startRecord()
        }
    }

    /** 关闭ExecutorService */
    private fun stopService() {
        executorService.shutdown()
        try {
            if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
                executorService.shutdownNow()
            }
        } catch (e: InterruptedException) {
            executorService.shutdownNow()
        }
    }

    /** 初始化并开始处理数据 */
    private fun initDataQueue() {
        isClosed = false
        dataQueue!!.clear()
        while (!isClosed) {
            var data = dataQueue!!.poll()
            while (data != null && !isClosed) {
                val bytes = toByteArray(data)
                sendPcm(bytes)
                data = dataQueue!!.poll()
            }
            try {
                Thread.sleep(10)
            } catch (e: Exception) {
                e.fillInStackTrace()
            }
        }
    }


    /** short[]转换为byte[] */
    private fun toByteArray(pcm: ShortArray): ByteArray {
        val size = pcm.size
        val dest = ByteArray(size shl 1)
        for (i in 0 until size) {
            dest[i * 2] = pcm[i].toByte()
            dest[i * 2 + 1] = (pcm[i].toInt() shr 8).toByte()
        }
        return dest
    }


    /**
     * ********************************************************************************************
     */
    private var connect: HttpURLConnection? = null
    private var os: OutputStream? = null
    private fun initHttp(link: String) {
        try {
            val url = URL(link)
            connect = url.openConnection() as HttpURLConnection
            connect!!.requestMethod = "POST"
            connect!!.connectTimeout = 10000
            connect!!.useCaches = false
            connect!!.doOutput = true
            connect!!.doInput = false
            connect!!.setRequestProperty("Transfer-Encoding", "chunked")
            connect!!.setChunkedStreamingMode(647)
            connect!!.connect()
            os = connect!!.outputStream
        }catch (e:Exception){
            talkSocket.onNext(true)
        }

    }

    /**
     * 发送数据
     *
     * @param byteArray
     */
    private fun sendPcm(byteArray: ByteArray) {
        try {
            os?.write(byteArray)
        } catch (e: Exception) {
            talkSocket.onNext(true)
        }

    }

    /** 关闭链接 */
    private fun closeHttp() {
        try {
            os?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

        connect?.disconnect()
        connect = null
    }


//    /**
//     */
//    private fun savePcm() {
//        try {
//            val file = File(getParentFile(BaseApp.application).absolutePath + "/audio.pcm")
//            if (!file.exists()) file.createNewFile()
//            val fos = FileOutputStream(file)
//            val bos = BufferedOutputStream(fos)
//            val dos = DataOutputStream(bos)
//            val buffer = ShortArray(bufferSize)
//            isRecording = true
//            while (isRecording) {
//                Log.e("录音====", "$bufferSize       $audioRecord     $dataQueue")
//                val read = audioRecord!!.read(buffer, 0, bufferSize)
//                for (i in 0 until read) {
//                    dos.writeShort(buffer[i].toInt())
//                }
//            }
//            stopRecord()
//            dos.close()
//            bos.close()
//            fos.close()
//        } catch (e: IOException) {
//            e.printStackTrace()
//        }
//    }
//
//    /**
//     */
//    private var audioTrack: AudioTrack? = null
//    private fun initTrack(bufferSize: Int) {
//        audioTrack = AudioTrack(
//            AudioManager.STREAM_MUSIC,
//            AUDIO_SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
//            AUDIO_ENCODING, bufferSize, AudioTrack.MODE_STREAM
//        )
//        if (audioTrack!!.state != AudioTrack.STATE_UNINITIALIZED) {
//            audioTrack!!.play()
//        }
//    }
//
//    fun play() {
//        println("开始播放声音================")
//        try {
//            val file = File(mContext.filesDir.path + "/audio.pcm")
//            val length = (file.length() / 2).toInt()
//            val shorts = ShortArray(length)
//            val fis = FileInputStream(file)
//            val bis = BufferedInputStream(fis)
//            val dis = DataInputStream(bis)
//            var i = 0
//            while (dis.available() > 0) {
//                shorts[i] = dis.readShort()
//                i++
//            }
//            fis.close()
//            bis.close()
//            dis.close()
//            initTrack(length)
//            audioTrack!!.write(shorts, 0, length)
//            audioTrack!!.stop()
//        } catch (e: IOException) {
//            e.printStackTrace()
//        }
//    }
//
//    private fun destroyTrack() {
//        if (audioTrack != null) {
//            audioTrack!!.stop()
//            audioTrack!!.release()
//            audioTrack = null
//        }
//    }

    /**
     */
    companion object {
        //音频输入-麦克风
        //    private static final int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;
        private const val AUDIO_INPUT = MediaRecorder.AudioSource.MIC

        //音频采样率
        private const val AUDIO_SAMPLE_RATE = 8000

        //声道 音频声道
        private const val AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO

        //编码 音频采样位
        private const val AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT

        /**
         */ //录音状态
        const val STATUS_READY = 0x10

        //录音开始
        const val STATUS_START = 0x11

        //录音中
        const val STATUS_RECORDING = 0x12

        //录音停止
        const val STATUS_STOP = 0x13
    }

}